package com.ocm.core.domain;

import java.io.InputStream;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;

import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Value;

import org.apache.jackrabbit.value.ValueFactoryImpl;

import com.ocm.core.exception.ExceptionCode;
import com.ocm.core.exception.OCMRuntimeException;
import com.ocm.core.exception.UnsupportTypeException;
import com.ocm.core.exception.TypeCodeException;
import com.ocm.core.service.AssociationTypeService;
import com.ocm.core.service.JCRService;
import com.ocm.core.util.DateUtil;

public enum PropertyType {
   STRING(0), INTEGER(1), DOUBLE(2), DATE(3), BOOLEAN(4), LONGSTRING(5), INPUTSTREAM(6), LONG(7), OBJECT(8);

   private int propertyType;

   public int getPropertyType() {
      return propertyType;
   }

   private PropertyType(int propertyType) {
      this.propertyType = propertyType;
   }

   public static PropertyType getPropertyType(int type) throws UnsupportTypeException {
      PropertyType propertyTypeObject = null;
      switch (type) {
         case 0:
            propertyTypeObject = PropertyType.STRING;
            break;
         case 1:
            propertyTypeObject = PropertyType.INTEGER;
            break;
         case 2:
            propertyTypeObject = PropertyType.DOUBLE;
            break;
         case 3:
            propertyTypeObject = PropertyType.DATE;
            break;
         case 4:
            propertyTypeObject = PropertyType.BOOLEAN;
            break;
         case 5:
            propertyTypeObject = PropertyType.LONGSTRING;
            break;
         case 6:
            propertyTypeObject = PropertyType.INPUTSTREAM;
            break;
         case 7:
            propertyTypeObject = PropertyType.LONG;
            break;
         case 8:
            propertyTypeObject = PropertyType.OBJECT;
            break;
         default:
            throw new UnsupportTypeException(ExceptionCode.instance(TypeCodeException.class,
                  TypeCodeException.PROPERTYTYPE));
      }
      return propertyTypeObject;
   }

   public Value convertValue(Object value) throws UnsupportTypeException, RepositoryException {
      Value result = null;
      switch (this) {
         case STRING:
         case LONGSTRING:
            value = (value == null) ? "" : value;
            result = ValueFactoryImpl.getInstance().createValue((String) value);
            break;
         case BOOLEAN:
            value = (value == null) ? Boolean.FALSE : value;
            result = ValueFactoryImpl.getInstance().createValue((Boolean) value);
            break;
         case DATE:
            try {
               if (value != null && value instanceof String && ("" + value).trim().length() > 0){
                  result = ValueFactoryImpl.getInstance().createValue((Calendar) DateUtil.convertCalendar("" +value));
               }else if (value != null && value instanceof Date){
                  result = ValueFactoryImpl.getInstance().createValue((Calendar) DateUtil.convertCalendar((Date)value));
               }else if (value == null){
                  result = null;
               }
            }
            catch (ParseException e) {
               throw new RepositoryException(e);
            }
            break;
         case DOUBLE:
            value = value == null ? 0.0 : value;
            result = ValueFactoryImpl.getInstance().createValue((Double) value);
            break;
         case INTEGER:
            value = value == null ? 0 : value;
            result = ValueFactoryImpl.getInstance().createValue((Integer) value);
            break;
         case INPUTSTREAM:
            value = value == null ? null : value;
            result = ValueFactoryImpl.getInstance().createValue(
                  ValueFactoryImpl.getInstance().createBinary((InputStream) value));
            break;
         case LONG:
            value = value == null ? 0L : value;
            result = ValueFactoryImpl.getInstance().createValue((Long) value);
            break;
         case OBJECT:
            if (value != null){
               result = ValueFactoryImpl.getInstance().createValue((Node) value);
            }
            break;
         default:
            throw new UnsupportTypeException(ExceptionCode.instance(TypeCodeException.class,
                  TypeCodeException.PROPERTYTYPE));
      }
      return result;
   }


   public Object convertToJavaType(Property property, boolean hasPropertyObject, String objectConfig, JCRService jcrService) throws UnsupportTypeException {
      Object result = null;
      try {
         switch (this) {
            case STRING:
            case LONGSTRING:
               result =  property.getValue().getString();
               break;
            case BOOLEAN:
               result = property.getValue().getBoolean();
               break;
            case DATE:
               result = DateUtil.convertDate(property.getValue().getDate());
               break;
            case DOUBLE:
               result = property.getValue().getDouble();
               break;
            case INTEGER:
               result = (new Long(property.getValue().getLong())).intValue();
               break;
            case INPUTSTREAM:
               result = (InputStream) property.getValue().getBinary().getStream();
               break;
            case LONG:
               result = property.getValue().getLong();
               break;
            case OBJECT:
               AssociationType associatedType = PropertyType.getAssociatedType(objectConfig);
               AssociationTypeService associationTypeService = associatedType.getAssociationTypeService(jcrService);
               if (hasPropertyObject){
                  result = associationTypeService.getPropertyObject(property);
               }else {
                  result = associationTypeService.getPropertyValue(property);
               }
               break;
            default:
               throw new UnsupportTypeException(ExceptionCode.instance(TypeCodeException.class,
                     TypeCodeException.PROPERTYTYPE));
         }
      } catch (Exception e){
         throw new OCMRuntimeException(e);
      }
      return result;
   }
   
   public static AssociationType getAssociatedType(String objectConfig) throws UnsupportTypeException{
      String[] result = parse(objectConfig);
      return AssociationType.getAssociationType(result[1]);
   }

   public static String[] parse(String objectConfig){
      String[] result = objectConfig.split("\\|");
      return result;
   }
}
